package com.zjb.demo.system.mapper;

import com.mybatisflex.core.BaseMapper;
import com.mybatisflex.core.query.QueryChain;
import com.mybatisflex.core.query.QueryWrapper;
import com.zjb.demo.system.domain.SysMenu;
import org.apache.ibatis.annotations.Mapper;

import java.util.List;

import static com.mybatisflex.core.query.QueryMethods.distinct;
import static com.mybatisflex.core.query.QueryMethods.ifNull;
import static com.zjb.demo.system.domain.table.SysMenuTableDef.SYS_MENU;
import static com.zjb.demo.system.domain.table.SysRoleTableDef.SYS_ROLE;
import static com.zjb.demo.system.domain.table.SysUserRoleTableDef.SYS_USER_ROLE;
import static com.zjb.demo.system.domain.table.SysRoleMenuTableDef.SYS_ROLE_MENU;

/**
 * @author 庄佳彬
 * @since 2023/12/28 23:07
 */
@Mapper
public interface SysMenuMapper extends BaseMapper<SysMenu> {
    /**
     * 根据角色ID查询对应角色所拥有的菜单权限
     *
     * @param roleId 角色ID
     * @return 菜单权限列表
     */
    default List<String> selectMenuPermsByRoleId(Long roleId) {
        return QueryChain.of(this)
                .select(distinct(SYS_MENU.PERMS))
                .from(SYS_MENU)
                .leftJoin(SYS_ROLE_MENU)
                .on(SYS_MENU.MENU_ID.eq(SYS_ROLE_MENU.MENU_ID))
                .where(SYS_ROLE_MENU.ROLE_ID.eq(roleId))
                .and(SYS_MENU.STATUS.eq("0"))
                .objListAs(String.class);
    }

    /**
     * 根据用户ID查询该用户所拥有的菜单权限列表
     *
     * @param userId 用户ID
     * @return 菜单权限列表
     */
    default List<String> selectMenuPermsByUserId(Long userId) {
        return QueryChain.of(this)
                .select(distinct(SYS_MENU.PERMS))
                .from(SYS_MENU)
                .leftJoin(SYS_ROLE_MENU)
                .on(SYS_MENU.MENU_ID.eq(SYS_ROLE_MENU.MENU_ID))
                .leftJoin(SYS_USER_ROLE)
                .on(SYS_ROLE_MENU.ROLE_ID.eq(SYS_USER_ROLE.ROLE_ID))
                .leftJoin(SYS_ROLE)
                .on(SYS_USER_ROLE.ROLE_ID.eq(SYS_ROLE.ROLE_ID))
                .where(SYS_USER_ROLE.USER_ID.eq(userId))
                .and(SYS_MENU.STATUS.eq("0"))
                .and(SYS_ROLE.STATUS.eq("0"))
                .objListAs(String.class);
    }

    /**
     * 选择所有的菜单树
     *
     * @return 所有的菜单列表
     */
    default List<SysMenu> selectMenuTreeAll() {
        return QueryChain.of(this)
                .select(distinct(SYS_MENU.MENU_ID),
                        SYS_MENU.PARENT_ID,
                        SYS_MENU.MENU_NAME,
                        SYS_MENU.PATH,
                        SYS_MENU.COMPONENT,
                        SYS_MENU.QUERY,
                        SYS_MENU.VISIBLE,
                        SYS_MENU.STATUS,
                        SYS_MENU.PERMS,
                        SYS_MENU.IS_FRAME,
                        SYS_MENU.IS_CACHE,
                        SYS_MENU.MENU_TYPE,
                        SYS_MENU.ICON,
                        SYS_MENU.ORDER_NUM,
                        SYS_MENU.CREATE_TIME)
                .from(SYS_MENU)
                .where(SYS_MENU.MENU_TYPE.in(List.of("M", "C")))
                .and(SYS_MENU.STATUS.eq("0"))
                .orderBy(SYS_MENU.PARENT_ID.asc(), SYS_MENU.ORDER_NUM.asc())
                .list();
    }

    default List<SysMenu> selectMenuTreeByUserId(Long userId) {
        return QueryChain.of(this)
                .select(distinct(SYS_MENU.MENU_ID),
                        SYS_MENU.PARENT_ID,
                        SYS_MENU.MENU_NAME,
                        SYS_MENU.PATH,
                        SYS_MENU.COMPONENT,
                        SYS_MENU.QUERY,
                        SYS_MENU.VISIBLE,
                        SYS_MENU.STATUS,
                        ifNull(SYS_MENU.PERMS.getName(), "").as("perms"),
                        SYS_MENU.IS_FRAME,
                        SYS_MENU.IS_CACHE,
                        SYS_MENU.MENU_TYPE,
                        SYS_MENU.ICON,
                        SYS_MENU.ORDER_NUM,
                        SYS_MENU.CREATE_TIME)
                .from(SYS_MENU)
                .leftJoin(SYS_ROLE_MENU)
                .on(SYS_MENU.MENU_ID.eq(SYS_ROLE_MENU.MENU_ID))
                .leftJoin(SYS_USER_ROLE)
                .on(SYS_ROLE_MENU.ROLE_ID.eq(SYS_USER_ROLE.ROLE_ID))
                .leftJoin(SYS_ROLE)
                .on(SYS_USER_ROLE.ROLE_ID.eq(SYS_ROLE.ROLE_ID))
                .where(SYS_USER_ROLE.USER_ID.eq(userId))
                .and(SYS_MENU.MENU_TYPE.in(List.of("M", "C")))
                .and(SYS_MENU.STATUS.eq("0"))
                .and(SYS_ROLE.STATUS.eq("0"))
                .orderBy(SYS_MENU.PARENT_ID.asc(), SYS_MENU.ORDER_NUM.asc())
                .list();
    }

    /**
     * 选择菜单列表
     *
     * @param menu 菜单对象
     * @return 菜单列表
     */
    default List<SysMenu> selectMenuList(SysMenu menu) {
        return QueryChain.of(this)
                .select(SYS_MENU.MENU_ID,
                        SYS_MENU.PARENT_ID,
                        SYS_MENU.MENU_NAME,
                        SYS_MENU.PATH,
                        SYS_MENU.COMPONENT,
                        SYS_MENU.QUERY,
                        SYS_MENU.VISIBLE,
                        SYS_MENU.STATUS,
                        ifNull(SYS_MENU.PERMS.getName(), "").as("perms"),
                        SYS_MENU.IS_FRAME,
                        SYS_MENU.IS_CACHE,
                        SYS_MENU.MENU_TYPE,
                        SYS_MENU.ICON,
                        SYS_MENU.ORDER_NUM,
                        SYS_MENU.CREATE_TIME)
                .from(SYS_MENU)
                .where(SYS_MENU.MENU_NAME.like(menu.getMenuName()))
                .and(SYS_MENU.VISIBLE.eq(menu.getVisible()))
                .and(SYS_MENU.STATUS.eq(menu.getStatus()))
                .orderBy(SYS_MENU.PARENT_ID.asc(), SYS_MENU.ORDER_NUM.asc())
                .list();
    }


    default List<SysMenu> selectMenuListByUserId(SysMenu menu, Long userId) {
        return QueryChain.of(this)
                .select(SYS_MENU.MENU_ID,
                        SYS_MENU.PARENT_ID,
                        SYS_MENU.MENU_NAME,
                        SYS_MENU.PATH,
                        SYS_MENU.COMPONENT,
                        SYS_MENU.QUERY,
                        SYS_MENU.VISIBLE,
                        SYS_MENU.STATUS,
                        ifNull(SYS_MENU.PERMS.getName(), "").as("perms"),
                        SYS_MENU.IS_FRAME,
                        SYS_MENU.IS_CACHE,
                        SYS_MENU.MENU_TYPE,
                        SYS_MENU.ICON,
                        SYS_MENU.ORDER_NUM,
                        SYS_MENU.CREATE_TIME)
                .from(SYS_MENU)
                .leftJoin(SYS_ROLE_MENU)
                .on(SYS_MENU.MENU_ID.eq(SYS_ROLE_MENU.MENU_ID))
                .leftJoin(SYS_USER_ROLE)
                .on(SYS_ROLE_MENU.ROLE_ID.eq(SYS_USER_ROLE.ROLE_ID))
                .where(SYS_USER_ROLE.USER_ID.eq(userId))
                .and(SYS_MENU.MENU_NAME.like(menu.getMenuName()))
                .and(SYS_MENU.VISIBLE.eq(menu.getVisible()))
                .and(SYS_MENU.STATUS.eq(menu.getStatus()))
                .orderBy(SYS_MENU.PARENT_ID.asc(), SYS_MENU.ORDER_NUM.asc())
                .list();
    }

    /**
     * 根据角色ID和菜单检查方式，查询指定角色所关联的菜单列表
     * @param roleId 角色ID
     * @param menuCheckStrictly 菜单检查方式，true表示严格检查（不包括该角色未关联的父菜单），false表示不严格检查（包括该角色未关联的父菜单）
     * @return 菜单ID列表
     */
    default List<Long> selectMenuListByRoleId(Long roleId, Boolean menuCheckStrictly) {
        var mainQuery = QueryWrapper.create()
                .select(SYS_MENU.MENU_ID)
                .from(SYS_MENU)
                .leftJoin(SYS_ROLE_MENU)
                .on(SYS_MENU.MENU_ID.eq(SYS_ROLE_MENU.MENU_ID))
                .where(SYS_ROLE_MENU.ROLE_ID.eq(roleId));
        if (menuCheckStrictly) {
            var subQuery = QueryWrapper.create()
                    .select(SYS_MENU.PARENT_ID)
                    .from(SYS_MENU)
                    .leftJoin(SYS_ROLE_MENU)
                    .on(SYS_MENU.MENU_ID.eq(SYS_ROLE_MENU.MENU_ID))
                    .where(SYS_ROLE_MENU.ROLE_ID.eq(roleId));
            mainQuery = mainQuery
                    .and(SYS_MENU.MENU_ID.notIn(subQuery));
        }
        mainQuery = mainQuery
                .orderBy(SYS_MENU.PARENT_ID.asc(), SYS_MENU.ORDER_NUM.asc());
        return selectObjectListByQueryAs(mainQuery, Long.class);
    }

}
